home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / tcp_ip / os2 / pmnos11s / kernel.c < prev    next >
Text File  |  1993-09-08  |  20KB  |  779 lines

  1. /* Non pre-empting synchronization kernel, machine-independent portion
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.     Preemptive kernel copyright 1991, 1992, 1993 Walt Corey KZ1F
  4.  */
  5.  
  6. #define    SUSPEND_PROC    1
  7. #undef    PROCTRACE        /* kernel debugging */
  8. #undef    PROCLOG            /* debugging */
  9.  
  10. #if defined(OS2)
  11. #define INCL_BASE
  12. #define INCL_DOS
  13. #define INCL_WIN
  14. #define INCL_DOSPROCESS
  15. #define INCL_DOSSEMAPHORES
  16. #include <os2.h>
  17. #endif
  18. #if    defined(PROCLOG) || defined(PROCTRACE)
  19. #include <stdio.h>
  20. #endif
  21. #if defined(OS2)
  22. #include <stdlib.h>
  23. #include <process.h>
  24. #include <setjmp.h>
  25. #include <stdio.h>
  26. #include <stddef.h>        /* for _threadid */
  27. #define UM_ERROR WM_USER + 107
  28. #else
  29. #include <dos.h>
  30. #include <setjmp.h>
  31. #endif
  32. #include "global.h"
  33. #include "mbuf.h"
  34. #include "proc.h"
  35. #include "timer.h"
  36. #include "socket.h"
  37. #include "daemon.h"
  38. #include "hardware.h"
  39.  
  40. #ifdef    PROCLOG
  41. FILE *proclog;
  42. FILE *proctrace;
  43. #endif
  44. int Stkchk = 0;
  45. struct proc *Curproc;        /* Currently running process */
  46. struct proc *Rdytab;        /* Processes ready to run (not including curproc) */
  47. struct proc *Waittab[PHASH];    /* Waiting process list */
  48. struct proc *Susptab;        /* Suspended processes */
  49. static struct mbuf *Killq;
  50.  
  51. #if defined(OS2)
  52. void * tss_array[100];     /* array for 100 thread-specific pointers */
  53. APIRET APIENTRY MyExceptionHandler(EXCEPTIONREPORTRECORD *,
  54.                                    EXCEPTIONREGISTRATIONRECORD *,
  55.                                    CONTEXTRECORD *,
  56.                                    PVOID);
  57.  
  58. int fInCriticalSection;     /* are we in a critical section */
  59. static unsigned long semRdyWaitQ;
  60. void strtTask(void * pv);
  61. /*
  62. Since we can have multiple tasks running and the existing system
  63. is based on a global to specify the proc strcture addr, we will
  64. change that to return same based on task id
  65. */
  66. #endif
  67.  
  68. static void addproc __ARGS((struct proc *entry));
  69. static void delproc __ARGS((struct proc *entry));
  70.  
  71. /* Create a process descriptor for the main function. Must be actually
  72.  * called from the main function!
  73.  * Note that standard I/O is NOT set up here.
  74.  */
  75. struct proc *
  76. mainproc(name)
  77. char *name;
  78. {
  79.     register struct proc *pp;
  80.     register unsigned k;
  81.     register int16 *p;
  82.  
  83.     /* Create process descriptor */
  84.     pp = (struct proc *)callocw(1,sizeof(struct proc));
  85.  
  86.     /* Create name */
  87.     pp->name = strdup(name);
  88. #if !defined(AMIGA) && !defined(OS2)
  89.     pp->stksize = _stklen / sizeof(int16);
  90.     pp->stack = (p = MK_FP(_SS,0));
  91.     k = _SP / sizeof(int16);
  92.         while(k-- > 0) *p++ = STACKPAT;
  93. #endif
  94. #if defined(OS2)
  95.     pp->stksize = 0;
  96. #endif
  97. #if defined(AMIGA)
  98.     init_psetup(pp);
  99. #endif
  100.     /* Make current */
  101.     pp->state = READY;
  102.     Curproc = pp;
  103. #if defined(OS2)
  104.     DosCreateEventSem(NULL, &pp->sem, 0, TRUE);
  105. #endif
  106. #ifdef    PROCLOG
  107.     proclog = fopen("proclog",APPEND_TEXT);
  108.     proctrace = fopen("proctrace",APPEND_TEXT);
  109. #endif
  110.     return pp;
  111. }
  112. /* Create a new, ready process and return pointer to descriptor.
  113.  * The general registers are not initialized, but optional args are pushed
  114.  * on the stack so they can be seen by a C function.
  115.  */
  116. struct proc *
  117. newproc(name,stksize,pc,iarg,parg1,parg2,freeargs)
  118. char *name;        /* Arbitrary user-assigned name string */
  119. unsigned int stksize;    /* Stack size in words to allocate */
  120. void (*pc)();        /* Initial execution address */
  121. int iarg;        /* Integer argument (argc) */
  122. void *parg1;        /* Generic pointer argument #1 (argv) */
  123. void *parg2;        /* Generic pointer argument #2 (session ptr) */
  124. int freeargs;        /* If set, free arg list on parg1 at termination */
  125. {
  126.     register struct proc *pp;
  127.     int i;
  128.  
  129. #if defined(OS2)
  130.     TID tid;
  131. #else
  132.     if(Stkchk)
  133.         chkstk();
  134. #endif
  135.     /* Create process descriptor */
  136.     pp = (struct proc *)callocw(1,sizeof(struct proc));
  137.  
  138.     /* Create name */
  139.     pp->name = strdup(name);
  140.  
  141.     /* Allocate stack */
  142. #if defined(AMIGA) 
  143.     stksize += 2000;    /* DOS overhead */
  144. #endif
  145.     pp->stksize = stksize;
  146.    pp->stack = NULL;
  147. #if !defined(OS2)
  148.     if((pp->stack = (int16 *)malloc(sizeof(int16)*stksize)) == NULL){
  149.         free(pp->name);
  150.         free((char *)pp);
  151.         return NULLPROC;
  152.     }
  153.     /* Initialize stack for high-water check */
  154.     for(i=0;i<stksize;i++)
  155.         pp->stack[i] = STACKPAT;
  156. #endif
  157.  
  158.     /* Do machine-dependent initialization of stack */
  159.     psetup(pp,iarg,parg1,parg2,pc);
  160.  
  161.     pp->freeargs = freeargs;
  162.     pp->iarg = iarg;
  163.     pp->parg1 = parg1;
  164.     pp->parg2 = parg2;
  165.     
  166.     /* Inherit creator's input and output sockets */
  167.     usesock(Curproc->input);
  168.     pp->input = Curproc->input;
  169.     usesock(Curproc->output);
  170.     pp->output = Curproc->output;
  171. #if defined(OS2)
  172.     pp->pc = pc;
  173. #endif
  174.  
  175.     /* Add to ready process table */
  176.     pp->state = READY;
  177. #if defined(OS2)
  178.    i = pp->stksize * sizeof(int16);
  179.    i -= i % 8192;
  180.    i += 8192;
  181.    pp->stksize = 0;
  182.     tid = (TID)_beginthread(strtTask,
  183.                 pp->stack,
  184.                 i,
  185.                 pp);
  186.    DosSleep(100); /* give it a chance to start */
  187. #else
  188.     addproc(pp);
  189. #endif
  190.     return pp;
  191. }
  192.  
  193. #if defined(OS2)
  194. void killproc(struct proc *pp)
  195. {
  196. char **argv;
  197.     if (pp == NULLPROC)     /* dont know why this would be but...*/
  198.     return;
  199.     pp->fTerminate = 1;     /* mark for termination */
  200.     psignal(pp, 0);        /* wake up those waiting for this to die */
  201.     stop_timer(&pp->alarm);
  202.     freesock(pp);
  203.     close_s(pp->input);
  204.     close_s(pp->output);
  205.     if (Curproc != pp)        /* dont queue ourselves */
  206.        alert(pp, EABORT);
  207.     /* Free allocated memory resources */
  208.     if(pp->freeargs){
  209.         argv = pp->parg1;
  210.         while(pp->iarg-- != 0)
  211.             free(*argv++);
  212.         free(pp->parg1);
  213.     }
  214.     free(pp->name);
  215.     free(pp->outbuf);
  216.     return;
  217. }
  218. void killself()
  219. {
  220.     killproc(Curproc);
  221.     while (1)
  222.     pwait(NULL);
  223. }
  224.  
  225. /* Process used by processes that want to kill themselves */
  226. void
  227. killer(i,v1,v2)
  228. int i;
  229. void *v1;
  230. void *v2;
  231. {
  232.     struct proc *pp;
  233.     struct mbuf *bp;
  234.  
  235.     for(;;){
  236.         while(Killq == NULLBUF)
  237.             pwait(&Killq);
  238.         bp = dequeue(&Killq);
  239.         pullup(&bp,(char *)&pp,sizeof(pp));
  240.         free_p(bp);
  241.         if(pp != Curproc) {    /* We're immortal */
  242. /*            free(pp->stack);*/
  243.             free((char *)pp);
  244.             }
  245.     }                        
  246. }
  247.  
  248. #else
  249. /* Free resources allocated to specified process. If a process wants to kill */
  250.  * itself, the reaper is called to do the dirty work. This avoids some
  251.  * messy situations that would otherwise occur, like freeing your own stack.
  252.  */
  253. void
  254. killproc(pp)
  255. register struct proc *pp;
  256. {
  257.     char **argv;
  258.  
  259.     if(pp == NULLPROC)
  260.         return;
  261.     /* Don't check the stack here! Will cause infinite recursion if
  262.      * called from a stack error
  263.      */
  264.  
  265.     if(pp == Curproc)
  266.         killself();    /* Doesn't return */
  267.  
  268.     /* Close any open sockets */
  269.     freesock(pp);
  270.  
  271.     close_s(pp->input);
  272.     close_s(pp->output);
  273.  
  274.     /* Stop alarm clock in case it's running */
  275.     stop_timer(&pp->alarm);
  276.  
  277.     /* Alert everyone waiting for this proc to die */
  278.     psignal(pp,0);
  279.  
  280.     /* Remove from appropriate table */
  281.     delproc(pp);
  282.  
  283. #ifdef    PROCLOG
  284.     fprintf(proclog,"id %lx name %s stack %u/%u\n",ptol(pp),
  285.         pp->name,stkutil(pp),pp->stksize);
  286.     fclose(proclog);
  287.     proclog = fopen("proclog",APPEND_TEXT);
  288.     proctrace = fopen("proctrace",APPEND_TEXT);
  289. #endif
  290.     /* Free allocated memory resources */
  291.     if(pp->freeargs){
  292.         argv = pp->parg1;
  293.         while(pp->iarg-- != 0)
  294.             free(*argv++);
  295.         free(pp->parg1);
  296.     }
  297.     free(pp->name);
  298. #if !defined(OS2)
  299.     free(pp->stack);
  300. #endif
  301.     free(pp->outbuf);
  302. #if !defined(OS2)
  303.     free((char *)pp);
  304. #endif
  305. }
  306. /* Terminate current process by sending a request to the killer process.
  307.  * Automatically called when a process function returns. Does not return.
  308.  */
  309. void
  310. killself()
  311. {
  312.     register struct mbuf *bp;
  313.  
  314.     if(Curproc != NULLPROC){
  315.         bp = pushdown(NULLBUF,sizeof(Curproc));
  316.         memcpy(bp->data,(char *)&Curproc,sizeof(Curproc));
  317.         enqueue(&Killq,bp);
  318.     }
  319.     /* "Wait for me; I will be merciful and quick." */
  320.     for(;;)
  321.         pwait(NULL);
  322. }
  323. /* Process used by processes that want to kill themselves */
  324. void
  325. killer(i,v1,v2)
  326. int i;
  327. void *v1;
  328. void *v2;
  329. {
  330.     struct proc *pp;
  331.     struct mbuf *bp;
  332.  
  333.     for(;;){
  334.         while(Killq == NULLBUF)
  335.             pwait(&Killq);
  336.         bp = dequeue(&Killq);
  337.         pullup(&bp,(char *)&pp,sizeof(pp));
  338.         free_p(bp);
  339.         if(pp != Curproc)    /* We're immortal */
  340.             {
  341.             killproc(pp);
  342. #if defined(OS2)
  343.             free(pp->stack);
  344.             free((char *)pp);
  345.     }                        
  346. #endif
  347.     }                        
  348. }
  349. #endif
  350. #ifdef    SUSPEND_PROC
  351. /* Inhibit a process from running */
  352. void
  353. suspend(pp)
  354. struct proc *pp;
  355. {
  356.     if(pp == NULLPROC)
  357.         return;
  358.     if(pp != Curproc)
  359.         delproc(pp);    /* Running process isn't on any list */
  360.     pp->state |= SUSPEND;
  361.     if(pp != Curproc)
  362.         addproc(pp);    /* pwait will do it for us */
  363.     else
  364.         pwait(NULL);
  365. }
  366. /* Restart suspended process */
  367. void
  368. resume(pp)
  369. struct proc *pp;
  370. {
  371.     if(pp == NULLPROC)
  372.         return;
  373.     delproc(pp);    /* Can't be Curproc! */
  374.     pp->state &= ~SUSPEND;
  375.     addproc(pp);
  376. }
  377. #endif    /* SUSPEND_PROC */
  378.  
  379. /* Wakeup waiting process, regardless of event it's waiting for. The process
  380.  * will see a return value of "val" from its pwait() call.
  381.  */
  382. void
  383. alert(pp,val)
  384. struct proc *pp;
  385. int val;
  386. {
  387.     if(pp == NULLPROC)
  388.         return;
  389. #ifdef    notdef
  390.     if((pp->state & WAITING) == 0)
  391.         return;
  392. #endif
  393. #ifdef    PROCTRACE
  394.     tprintf("alert(%lx,%u) [%s]\n",ptol(pp),val,pp->name);
  395.     fflush(stdout);
  396. #endif
  397.     if(pp != Curproc)
  398.         delproc(pp);
  399.     pp->state &= ~WAITING;
  400.     pp->retval = val;
  401.     pp->event = 0;
  402.     if(pp != Curproc)
  403.         addproc(pp);
  404. }
  405.  
  406. /* Post a wait on a specified event and give up the CPU until it happens. The
  407.  * null event is special: it means "I don't want to block on an event, but let
  408.  * somebody else run for a while". It can also mean that the present process
  409.  * is terminating; in this case the wait never returns.
  410.  *
  411.  * Pwait() returns 0 if the event was signaled; otherwise it returns the
  412.  * arg in an alert() call. Pwait must not be called from interrupt level.
  413.  *
  414.  * Note that pwait can run with interrupts enabled even though it examines
  415.  * a few global variables that can be modified by psignal at interrupt time.
  416.  * These *seem* safe.
  417.  */
  418. extern int fInterruptDepth;
  419. int
  420. pwait(event)
  421. void *event;
  422. {
  423. #if defined(OS2)
  424.    struct mbuf *bp;
  425.    ULONG ulPostCt;
  426. #endif
  427.    struct proc *oldproc;
  428.     int tmp;
  429.  
  430.     extern int WDTick;
  431.     extern int WDCurr;
  432.  
  433.     WDCurr = WDTick;        /* reset watchdog timer value */
  434.  
  435.     if(Curproc != NULLPROC){    /* If process isn't terminating */
  436. #if !defined(OS2)
  437.         if(Stkchk)
  438.             chkstk();
  439. #endif
  440.         if(event == NULL)
  441.           {
  442.             /* Special case; just give up the processor.
  443.              *
  444.              * Optimization: if nothing else is ready, just return.
  445.              */
  446.             if(Rdytab == NULLPROC)
  447.                 return 0;
  448.           }
  449.        else
  450.          {
  451.             /* Post a wait for the specified event */
  452.             Curproc->event = event;
  453.             Curproc->state = WAITING;
  454.            }
  455. #if defined(OS2)
  456.             DosEnterCritSec();
  457.             if (!Curproc->fTerminate)
  458. #endif
  459.                 addproc(Curproc);
  460. #if defined(OS2)
  461.     DosExitCritSec();
  462. #endif
  463.     }
  464.     /* Look for a ready process and run it. If there are none,
  465.      * loop or halt until an interrupt makes something ready.
  466.      */
  467.     while(Rdytab == NULLPROC){
  468.         /* Give system back to upper-level multitasker, if any.
  469.          * Note that this function enables interrupts internally
  470.          * to prevent deadlock, but it restores our state
  471.          * before returning.
  472.          */
  473. #if !defined(OS2)
  474.         kbint();    /***/
  475. #endif
  476.         giveup();
  477.     }
  478.     /* Remove first entry from ready list */
  479.     DosEnterCritSec();
  480.     oldproc = Curproc;
  481.     Curproc = Rdytab;
  482.     delproc(Curproc);
  483.     DosExitCritSec();
  484.  
  485. #if !defined(OS2)
  486.     /* Now do the context switch.
  487.      * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
  488.      *
  489.      * If the old process has gone away, simply load the new process's
  490.      * environment. Otherwise, save the current process's state. Then if
  491.      * this is still the old process, load the new environment. Since the
  492.      * new task will "think" it's returning from the setjmp() with a return
  493.      * value of 1, the comparison with 0 will bypass the longjmp(), which
  494.      * would otherwise cause an infinite loop.
  495.      */
  496. #ifdef    PROCTRACE
  497.     if(strcmp(oldproc->name,Curproc->name) != 0){
  498.           tprintf("pwait -> %s(%d)\n",Curproc->name,!!Curproc->i_state);
  499.         fflush(stdout);
  500.     }
  501. #endif
  502.     /* Note use of comma operator to save old interrupt state only if
  503.      * oldproc is non-null
  504.      */
  505.     if(oldproc == NULLPROC
  506.      || (oldproc->i_state = istate(), setjmp(oldproc->env) == 0)){
  507.         /* We're still running in the old task; load new task context.
  508.          * The interrupt state is restored here in case longjmp
  509.          * doesn't do it (e.g., systems other than Turbo-C).
  510.          */
  511.         restore(Curproc->i_state);
  512.         longjmp(Curproc->env,1);
  513.     }
  514. #else
  515.     if (Curproc == oldproc) /* waiting on myself? */
  516.         return(0);
  517.     oldproc->i_state = istate();
  518.    if (fInterruptDepth)
  519.       tprintf("\nInterrupts are OFF!\n");
  520.    DosResetEventSem(oldproc->sem, &ulPostCt);
  521.     if (oldproc->fTerminate)
  522.          {
  523.          bp = pushdown(NULLBUF,sizeof(oldproc));
  524.          memcpy(bp->data,(char *)&oldproc,sizeof(oldproc));
  525.          enqueue(&Killq,bp);
  526.          DosPostEventSem(Curproc->sem);
  527.           _endthread();
  528.          }
  529.     DosPostEventSem(Curproc->sem);
  530.    DosWaitEventSem(oldproc->sem, SEM_INDEFINITE_WAIT);
  531.     Curproc = oldproc;
  532.  
  533. #endif
  534.  
  535.     /* At this point, we're running in the newly dispatched task */
  536.     tmp = Curproc->retval;
  537.     Curproc->retval = 0;
  538.  
  539.     /* Also restore the true interrupt state here, in case the longjmp
  540.      * DOES restore the interrupt state saved at the time of the setjmp().
  541.      * This is the case with Turbo-C's setjmp/longjmp.
  542.      */
  543. #if !defined(OS2)
  544.     restore(Curproc->i_state);
  545. #endif
  546.     return tmp;
  547. }
  548.  
  549. /* Make ready the first 'n' processes waiting for a given event. The ready
  550.  * processes will see a return value of 0 from pwait().  Note that they don't
  551.  * actually get control until we explicitly give up the CPU ourselves through
  552.  * a pwait(). Psignal may be called from interrupt level. It returns the
  553.  * number of processes that were woken up.
  554.  */
  555. int
  556. psignal(event,n)
  557. void *event;    /* Event to signal */
  558. int n;        /* Max number of processes to wake up */
  559. {
  560.     register struct proc *pp;
  561.     struct proc *pnext;
  562.     int i_state;
  563.     unsigned int hashval;
  564.     int cnt = 0;
  565.  
  566.     if(Stkchk)
  567.         chkstk();
  568.  
  569.     if(event == NULL)
  570.         return 0;        /* Null events are invalid */
  571.  
  572.     /* n = 0 means "signal everybody waiting for this event" */
  573.     if(n == 0)
  574.         n = 65535;
  575.  
  576.     hashval = phash(event);
  577.     i_state = dirps();
  578.     for(pp = Waittab[hashval];n != 0 && pp != NULLPROC;pp = pnext){
  579.         pnext = pp->next;
  580.         if(pp->event == event){
  581. #ifdef    PROCTRACE
  582.             if(i_state){
  583.                 tprintf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
  584.                  ptol(pp),pp->name);
  585.                 fflush(stdout);
  586.             }
  587. #endif
  588.             delproc(pp);
  589.             pp->state &= ~WAITING;
  590.             pp->retval = 0;
  591.             pp->event = NULL;
  592.             addproc(pp);
  593.             n--;
  594.             cnt++;
  595.         }
  596.     }
  597. #ifdef    SUSPEND_PROC
  598.     for(pp = Susptab;n != 0 && pp != NULLPROC;pp = pnext){
  599.         pnext = pp->next;
  600.         if(pp->event == event){
  601. #ifdef    PROCTRACE
  602.             if(i_state){
  603.                 tprintf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
  604.                  ptol(pp),pp->name);
  605.                 fflush(stdout);
  606.             }
  607. #endif /* PROCTRACE */
  608.             delproc(pp);
  609.             pp->state &= ~WAITING;
  610.             pp->event = 0;
  611.             pp->retval = 0;
  612.             addproc(pp);
  613.             n--;
  614.             cnt++;
  615.         }
  616.     }
  617. #endif    /* SUSPEND_PROC */
  618.     restore(i_state);
  619.     return cnt;
  620. }
  621.  
  622. /* Rename a process */
  623. void
  624. chname(pp,newname)
  625. struct proc *pp;
  626. char *newname;
  627. {
  628.     free(pp->name);
  629.     pp->name = strdup(newname);
  630. #if defined(PM)
  631.     if (Current)
  632.         WinSetWindowText(Current->hwndFrame, pp->name);
  633. #endif
  634. }
  635. /* Remove a process entry from the appropriate table */
  636. static void
  637. delproc(entry)
  638. register struct proc *entry;    /* Pointer to entry */
  639. {
  640.     int i_state;
  641.  
  642.     if(entry == NULLPROC)
  643.         return;
  644.  
  645.     i_state = dirps();
  646.     if(entry->next != NULLPROC)
  647.         entry->next->prev = entry->prev;
  648.     if(entry->prev != NULLPROC){
  649.         entry->prev->next = entry->next;
  650.     } else {
  651.         switch(entry->state){
  652.         case READY:
  653.             Rdytab = entry->next;
  654.             break;
  655.         case WAITING:
  656.             Waittab[phash(entry->event)] = entry->next;
  657.             break;
  658. #ifdef    SUSPEND_PROC
  659.         case SUSPEND:
  660.         case SUSPEND|WAITING:
  661.             Susptab = entry->next;
  662.             break;
  663. #endif
  664.         }
  665.     }
  666.     restore(i_state);
  667. }
  668. /* Append proc entry to end of appropriate list */
  669. static void
  670. addproc(entry)
  671. register struct proc *entry;    /* Pointer to entry */
  672. {
  673.     register struct proc *pp;
  674.     struct proc **head;
  675.     int i_state;
  676.  
  677.     if(entry == NULLPROC)
  678.         return;
  679.  
  680.     switch(entry->state){
  681.     case READY:
  682.         head = &Rdytab;
  683.         break;
  684.     case WAITING:
  685.         head = &Waittab[phash(entry->event)];
  686.         break;
  687. #ifdef    SUSPEND_PROC
  688.     case SUSPEND:
  689.     case SUSPEND|WAITING:
  690.         head = &Susptab;
  691.         break;
  692. #endif
  693.     }
  694.     entry->next = NULLPROC;
  695.     i_state = dirps();
  696.     if(*head == NULLPROC){
  697.         /* Empty list, stick at beginning */
  698.         entry->prev = NULLPROC;
  699.         *head = entry;
  700.     } else {
  701.         /* Find last entry on list */
  702.         for(pp = *head;pp->next != NULLPROC;pp = pp->next)
  703.             ;
  704.         pp->next = entry;
  705.         entry->prev = pp;
  706.     }
  707.     restore(i_state);
  708. }
  709. #if defined(OS2)
  710. #pragma map(_Exception,"MyExceptionHandler")
  711. #pragma handler(strtTask)
  712.  
  713. void strtTask(void *pv)
  714. {
  715. void *pvArgs[2];
  716. int i_state;
  717. HAB hab1;
  718. jmp_buf jbuf;          /* put the jump buffer in automatic storage */
  719.                            /*   so it is unique to this thread         */
  720. PTIB ptib;             /* to get the TIB pointer */
  721. PPIB ppib;
  722. struct proc *pp = (struct proc *)pv;
  723. unsigned int tid = *_threadid;   /* get the thread id */
  724.  
  725.     /* create a thread specific jmp_buf */
  726.     tss_array[tid] = (void *) jbuf;
  727.     if (!setjmp(jbuf))   /* provide a point to return to */
  728.        {
  729.        DosSetPrty(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
  730.        addproc(pp);
  731.        DosCreateEventSem(NULL, &pp->sem, 0, FALSE);
  732.        DosWaitEventSem(pp->sem, -1);
  733.        DosSetPrty(PRTYS_THREAD, PRTYC_REGULAR, 0, 0);
  734.        pvArgs[0] = pp->parg1;
  735.        pvArgs[1] = pp->parg2;
  736.        (*pp->pc)(pp->iarg, pp->parg1, pp->parg2);
  737.        }
  738.     killself();
  739.     return;
  740. }
  741. extern HWND hwndCmd;
  742. APIRET APIENTRY MyExceptionHandler(EXCEPTIONREPORTRECORD * report_rec,
  743.                                    EXCEPTIONREGISTRATIONRECORD * register_rec,
  744.                                    CONTEXTRECORD * context_rec,
  745.                                    PVOID dummy)
  746. {
  747. void *mp1;
  748. void *mp2;
  749. unsigned int tid;   /* get the thread id */
  750.  
  751.    tid = *_threadid;
  752.    /* check the exception flags */
  753.    if (EH_EXIT_UNWIND & report_rec->fHandlerFlags) /* exiting */
  754.       return XCPT_CONTINUE_SEARCH;
  755.  
  756.    if (EH_UNWINDING & report_rec->fHandlerFlags)   /* unwinding */
  757.       return XCPT_CONTINUE_SEARCH;
  758.  
  759.    if (EH_NESTED_CALL & report_rec->fHandlerFlags) /* nested exceptions */
  760.       return XCPT_CONTINUE_SEARCH;
  761.  
  762.    /* determine what the exception is */
  763.    if (report_rec->ExceptionNum == XCPT_ACCESS_VIOLATION) 
  764.       /* this is the one that is expected */
  765.       {
  766.       mp1 = malloc(sizeof(struct proc));
  767.       memcpy(mp1, Curproc, sizeof(struct proc));
  768.       mp2 = malloc(sizeof(EXCEPTIONREPORTRECORD));
  769.       memcpy(mp2, report_rec, sizeof(EXCEPTIONREPORTRECORD));
  770.       WinPostMsg(hwndCmd, UM_ERROR, MPFROMP(mp1), MPFROMP(mp2));
  771.       longjmp((int *)tss_array[tid],1);   /* return to the point of the */
  772.                                           /* setjmp call without        */
  773.                                           /* restarting the process  */
  774.       } /* endif */
  775.    return XCPT_CONTINUE_SEARCH;      /* if it is a different exception */
  776. }
  777.  
  778. #endif
  779.